/**
 * 
 */
package com.zufangbao.earth.web.controller.finance;

import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.demo2do.core.entity.Result;
import com.demo2do.core.persistence.support.Filter;
import com.demo2do.core.utils.DateUtils;
import com.demo2do.core.utils.JsonUtils;
import com.demo2do.core.utils.StringUtils;
import com.demo2do.core.web.interceptor.InfoMessage;
import com.demo2do.core.web.interceptor.MenuSetting;
import com.demo2do.core.web.resolver.Page;
import com.demo2do.core.web.resolver.Secure;
import com.zufangbao.earth.entity.security.Principal;
import com.zufangbao.earth.handler.PaymentHandler;
import com.zufangbao.earth.service.PrincipalService;
import com.zufangbao.sun.entity.company.corp.App;
import com.zufangbao.sun.entity.factoring.FactoringContract;
import com.zufangbao.sun.entity.finance.BatchPayDetail;
import com.zufangbao.sun.entity.finance.BatchPayRecord;
import com.zufangbao.sun.entity.finance.PayStatus;
import com.zufangbao.sun.entity.finance.PaymentInfo;
import com.zufangbao.sun.entity.order.Order;
import com.zufangbao.sun.entity.order.OrderStatus;
import com.zufangbao.sun.entity.order.RepaymentType;
import com.zufangbao.sun.service.AppService;
import com.zufangbao.sun.service.BatchPayRecordService;
import com.zufangbao.sun.service.FactoringContractService;
import com.zufangbao.sun.service.FinancePaymentRecordService;
import com.zufangbao.sun.service.OrderService;
import com.zufangbao.sun.service.PayService;

/**
 * @author mohanlan
 *
 */
@Controller
@RequestMapping("/payment")
@MenuSetting("menu-finance")
public class PaymentController {

	@Autowired
	private OrderService orderService;
	@Autowired
	private FinancePaymentRecordService financePaymentRecordService;
	@Autowired
	private AppService appService;
	@Autowired
	private FactoringContractService factoringContractService;
	@Autowired
	private PaymentHandler paymetHandler;
	@Autowired
	private PayService payService;
	@Autowired
	private BatchPayRecordService batchPayRecordService;
	@Autowired
	private PrincipalService principalService;

	/**
	 * return payment waiting list
	 * 
	 * @return
	 */
	@RequestMapping(value = { "/manage", "/waiting/factoring" })
	@MenuSetting("submenu-payment-manage")
	public ModelAndView factoring() {

		List<FactoringContract> factoringContractList = factoringContractService
				.loadAll(FactoringContract.class);

		List<PaymentInfo> paymentInfoList = paymetHandler
				.getPaidOrdersInFactoring();

		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-waiting-factoring");
		modelAndView.addObject("factoringContractList", factoringContractList);
		modelAndView.addObject("paymentInfoList", paymentInfoList);

		return modelAndView;

	}

	@RequestMapping("/waiting/agency")
	@MenuSetting("submenu-payment-manage")
	public ModelAndView agency() {

		List<App> appList = appService.loadAll(App.class);
		List<PaymentInfo> paymentInfoList = paymetHandler
				.getPaidOrdersNotInFactoring();

		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-waiting-agency");
		modelAndView.addObject("appList", appList);
		modelAndView.addObject("paymentInfoList", paymentInfoList);

		return modelAndView;

	}

	@RequestMapping(value = "/waiting/factoring/search", method = RequestMethod.GET)
	@MenuSetting("submenu-payment-manage")
	public ModelAndView waitingSearchInFactoring(
			@RequestParam(value = "factoringContract") String factoringContractId,
			@RequestParam(value = "repaymentType") String repaymentType) {
		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-waiting-factoring");
		List<PaymentInfo> paymentInfoList = new ArrayList<PaymentInfo>();
		if (!factoringContractId.isEmpty() && !repaymentType.isEmpty()) {
			paymentInfoList = paymetHandler.getOrdersByFactoringContract(
					Long.parseLong(factoringContractId),
					RepaymentType.fromValue(Integer.parseInt(repaymentType)));
		}

		if (factoringContractId.isEmpty() && repaymentType.isEmpty()) {
			paymentInfoList = paymetHandler.getPaidOrdersInFactoring();
		}

		List<FactoringContract> factoringContractList = factoringContractService
				.loadAll(FactoringContract.class);

		modelAndView.addObject("paymentInfoList", paymentInfoList);
		modelAndView.addObject("factoringContractId", factoringContractId);
		modelAndView.addObject("repaymentType", repaymentType);
		modelAndView.addObject("factoringContractList", factoringContractList);
		return modelAndView;
	}

	@RequestMapping(value = "/waiting/agency/search", method = RequestMethod.GET)
	@MenuSetting("submenu-payment-manage")
	public ModelAndView waitingSearchNotInFactoring(
			@RequestParam(value = "app") String appId) {
		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-waiting-agency");
		List<PaymentInfo> paymentInfoList = new ArrayList<PaymentInfo>();
		if (appId.isEmpty()) {
			paymentInfoList = paymetHandler.getPaidOrdersNotInFactoring();
		} else {
			paymentInfoList = paymetHandler.getPaidOrdersByApp(Long
					.parseLong(appId));
		}

		List<App> appList = appService.loadAll(App.class);

		modelAndView.addObject("paymentInfoList", paymentInfoList);
		modelAndView.addObject("appId", appId);
		modelAndView.addObject("appList", appList);
		return modelAndView;
	}

	@RequestMapping(value = "/factoring/doApply", method = RequestMethod.GET)
	@MenuSetting("submenu-payment-manage")
	public @ResponseBody String doApplyForFactoring(
			@RequestParam("orderIds") String orderIds,
			@RequestParam("remark") String remark, @Secure Principal principal) {

		Result result = paymetHandler.applyBatchPayForFactoring(orderIds,
				remark, principal);

		return JsonUtils.toJsonString(result);

	}

	@RequestMapping(value = "/agency/doApply", method = RequestMethod.GET)
	@MenuSetting("submenu-payment-manage")
	public @ResponseBody String doApplyForAgency(
			@RequestParam("orderIds") String orderIds,
			@RequestParam("remark") String remark, @Secure Principal principal) {

		Result result = paymetHandler.applyBatchPayForAgency(orderIds, remark,
				principal);

		return JsonUtils.toJsonString(result);

	}

	@RequestMapping(value = "/payForDirectBank")
	public ModelAndView directBankPay(
			@RequestParam("amount") BigDecimal amount,
			@RequestParam("receiveAccountName") String receiveAccountName,
			@RequestParam("receiveAccountNo") String receiveAccountNo,
			@RequestParam("remark") String remark,
			@RequestParam("batchPayRecordId") Long batchPayRecordId) {
		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-directbank-pay");

		modelAndView.addObject("amount", amount);
		modelAndView.addObject("receiveAccountName", receiveAccountName);
		modelAndView.addObject("receiveAccountNo", receiveAccountNo);
		modelAndView.addObject("remark", remark);
		modelAndView.addObject("batchPayRecordId", batchPayRecordId);
		return modelAndView;
	}

	@RequestMapping(value = "/directbank/doPay", method = RequestMethod.POST)
	public @ResponseBody String doPay(
			@RequestParam("accountNo") String accountNo,
			@RequestParam("batchPayRecordId") Long batchPayRecordId,
			@RequestParam("isInterbank") String isInterbank,
			@RequestParam("accountName") String accountName,
			@RequestParam("amount") String amount,
			@RequestParam("remark") String remark, @Secure Principal principal) {

		Result result = payService.batchPay(Boolean.parseBoolean(isInterbank),
				batchPayRecordId, accountNo, accountName,
				new BigDecimal(amount), remark, principal.getId());

		return JsonUtils.toJsonString(result);
	}

	@RequestMapping("/manage/apply")
	@MenuSetting("submenu-payment-manage")
	public ModelAndView apply(Page page) {
		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-manage-apply");

		com.demo2do.core.persistence.support.Order orderByTime = new com.demo2do.core.persistence.support.Order();
		orderByTime.add("modify_time", "DESC");

		List<BatchPayRecord> batchPayList = batchPayRecordService.list(
				BatchPayRecord.class,
				new Filter().addEquals("payStatus", PayStatus.NotPayed),
				orderByTime, page);

		modelAndView.addObject("batchPayList", batchPayList);
		return modelAndView;
	}

	@RequestMapping("/manage/success")
	@MenuSetting("submenu-payment-manage")
	public ModelAndView batchSuccess(Page page) {
		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-manage-success");

		com.demo2do.core.persistence.support.Order orderByTime = new com.demo2do.core.persistence.support.Order();
		orderByTime.add("modify_time", "DESC");

		List<BatchPayRecord> batchPayList = batchPayRecordService.list(
				BatchPayRecord.class,
				new Filter().addEquals("payStatus", PayStatus.Payed),
				orderByTime, page);

		modelAndView.addObject("batchPayList", batchPayList);
		return modelAndView;
	}

	@RequestMapping("/offline/{batchId}/payouting")
	public ModelAndView offlinePayOuting(@PathVariable("batchId") Long batchId) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-offline-payouting");

		modelAndView.addObject("batchId", batchId);

		return modelAndView;
	}

	@RequestMapping(value = "/offline/{batchId}/payouting", method = RequestMethod.POST)
	@InfoMessage("info.payment.payouting.success")
	public String offlineDoPayOuting(@PathVariable("batchId") Long batchId,
			@Secure Principal principal,
			@RequestParam("serialNo") String serialNo) {

		BatchPayRecord batchPayRecord = batchPayRecordService.load(
				BatchPayRecord.class, batchId);
		batchPayRecordService.batchPayout(batchPayRecord, principal.getId(),
				serialNo);

		return "redirect:/payment/manage/success";
	}

	/**
	 * return payment success list
	 * 
	 * @return
	 */
	@RequestMapping("/success")
	@MenuSetting("submenu-payment-success")
	public ModelAndView success(Page page, @Secure Principal principal) {
		Filter filter = new Filter();
		filter.addEquals("orderStatus", OrderStatus.PAYOUTING);
		com.demo2do.core.persistence.support.Order orderByPaymentTime = new com.demo2do.core.persistence.support.Order();
		orderByPaymentTime.add("payoutTime", "DESC");
		List<App> appList = this.principalService.get_can_access_app_list(principal);
		if(!principal.isSuperRole()){
			filter.addEquals("contract.app.id", appList.get(0).getId());
		}
		List<Order> orderList = orderService.list(Order.class, filter,
				orderByPaymentTime, page);

		ModelAndView modelAndView = new ModelAndView("finance/payment-success");
		modelAndView.addObject("role", principal.getAuthority());
		modelAndView.addObject("orderList", orderList);
		modelAndView.addObject("appList", appList);
		modelAndView.addObject("page", page);

		return modelAndView;

	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping("/waiting/search")
	public ModelAndView waitingSearch() {

		List<App> appList = appService.list(App.class,
				new Filter().addEquals("disabled", false));

		ModelAndView modelAndView = new ModelAndView(
				"finance/order-payment-waiting-search");
		modelAndView.addObject("appList", appList);

		return modelAndView;
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = "/waiting/search", method = RequestMethod.GET, params = "filter")
	@MenuSetting("submenu-payment-waiting")
	public ModelAndView waitingOnSearch(HttpServletRequest request,
			@RequestParam(value = "orderNo", required = false) String orderNo,
			@RequestParam(value = "appId", required = false) Long appId,
			Page page) {

		ModelAndView modelAndView = new ModelAndView("finance/payment-waiting");

		// create Filter first
		Filter filter = new Filter();
		if (!orderNo.isEmpty()) {
			filter.addEquals("orderNo", orderNo);
		}
		if (appId >= 0) {
			filter.addEquals("customer.app.id", appId);
		}

		List<Order> orderList = orderService.list(Order.class,
				filter.addEquals("orderStatus", OrderStatus.PAID), page);

		// handle query string
		String queryString = request.getQueryString();
		Map<String, String> queries = StringUtils.parseQueryString(queryString);
		if (queries.containsKey("page")) {
			queries.remove("page");
		}

		modelAndView.addObject("orderList", orderList);
		modelAndView.addObject("queryString",
				StringUtils.toQueryString(queries));

		return modelAndView;
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping("/success/search")
	public ModelAndView successSearch() {

		List<App> appList = appService.list(App.class,
				new Filter().addEquals("disabled", false));

		ModelAndView modelAndView = new ModelAndView(
				"finance/order-payment-success-search");
		modelAndView.addObject("appList", appList);

		return modelAndView;
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = "/success/search", method = RequestMethod.GET, params = "filter")
	@MenuSetting("submenu-payment-success")
	public ModelAndView successOnSearch(
			HttpServletRequest request,
			@Secure Principal principal,
			@RequestParam(value = "orderNo", required = false) String orderNo,
			@RequestParam(value = "appId", required = false) Long appId,
			@RequestParam(value = "startDate", required = false) String startDate,
			@RequestParam(value = "endDate", required = false) String endDate,
			Page page) {

		ModelAndView modelAndView = new ModelAndView("finance/payment-success");
		List<App> appList = this.principalService
				.get_can_access_app_list(principal);
		// create Filter first
		Filter filter = generateFilter(principal, orderNo, appId, startDate,
				endDate);
		com.demo2do.core.persistence.support.Order orderByTime = new com.demo2do.core.persistence.support.Order();
		orderByTime.add("payout_time", "DESC");
		List<Order> orderList = orderService.list(Order.class,
				filter.addEquals("orderStatus", OrderStatus.PAYOUTING),
				orderByTime, page);
		// handle query string
		String queryString = request.getQueryString();
		Map<String, String> queries = StringUtils.parseQueryString(queryString);
		if (queries.containsKey("page")) {
			queries.remove("page");
		}
		modelAndView.addObject("role", principal.getAuthority());
		modelAndView.addObject("startDate", startDate);
		modelAndView.addObject("app", appId);
		modelAndView.addObject("endDate", endDate);
		modelAndView.addObject("appList", appList);
		modelAndView.addObject("orderNo", orderNo);
		modelAndView.addObject("orderList", orderList);
		modelAndView.addObject("queryString",
				StringUtils.toQueryString(queries));

		return modelAndView;
	}

	private Filter generateFilter(Principal principal, String orderNo,
			Long appId, String startDate, String endDate) {
		Filter filter = new Filter();

		if (is_query_condition(orderNo)) {
			filter.addLike("orderNo", orderNo);
		}
		if (principal.is_app_role()) {
			filter.addEquals("customer.app.id", principal.getKeyId());
		} else if (is_query_condition(String.valueOf(appId))) {
			filter.addEquals("customer.app.id",appId );
		}
		if (is_query_condition(startDate)) {
			filter.addGreaterThan("payoutTime",
					DateUtils.parseDate(startDate, "yyyy-MM-dd"));
		}
		if (is_query_condition(endDate)) {
			filter.addLessThan(
					"payoutTime",
					DateUtils.addDays(
							DateUtils.parseDate(endDate, "yyyy-MM-dd"), 1));
		}
		return filter;
	}

	private boolean is_query_condition(String column) {
		return !StringUtils.isEmpty(column);
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping("/{orderId}/payouting")
	public ModelAndView payOuting(@PathVariable("orderId") Long orderId) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/order-payment-payouting");
		modelAndView.addObject("orderId", orderId);

		return modelAndView;
	}

	/**
	 * 
	 * @return
	 */
	@RequestMapping(value = "/{orderId}/payouting", method = RequestMethod.POST)
	@InfoMessage("info.payment.payouting.success")
	public String onPayOuting(@PathVariable("orderId") Long orderId,
			@Secure Principal principal,
			@RequestParam("paymentNo") String paymentNo) {

		Order order = orderService.load(Order.class, orderId);
		orderService.orderPayout(order, principal.getId(), paymentNo);

		return "redirect:/payment/success";
	}

	@RequestMapping("/{batchId}/detail")
	@MenuSetting("submenu-payment-manage")
	public ModelAndView batchPayRecordDetail(
			@PathVariable("batchId") Long batchPayRecordId) {

		BatchPayRecord batchPayRecord = batchPayRecordService.load(
				BatchPayRecord.class, batchPayRecordId);

		List<BatchPayDetail> batchPayDetails = batchPayRecordService
				.getDetailByBatchPay(batchPayRecordId);
		List<PaymentInfo> paymentInfoList = paymetHandler
				.changeBatchPayDetailsToPaymentInfo(batchPayDetails);

		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-batchpay-detail");
		modelAndView.addObject("batchPayRecord", batchPayRecord);
		modelAndView.addObject("paymentInfoList", paymentInfoList);

		return modelAndView;
	}

	@RequestMapping("/{batchId}/delete")
	public ModelAndView delete(@PathVariable("batchId") Long batchPayRecordId) {

		ModelAndView modelAndView = new ModelAndView(
				"finance/payment-delete-apply");
		modelAndView.addObject("batchId", batchPayRecordId);

		return modelAndView;
	}

	@RequestMapping(value = "/{batchId}/delete", method = RequestMethod.POST)
	@InfoMessage("info.batchpay.delete.success")
	public String delete(@PathVariable("batchId") Long batchPayRecordId,
			@Secure Principal principal) {

		batchPayRecordService.deleteBatchPayAndDetails(batchPayRecordId);

		return "redirect:/payment/waiting/factoring";

	}

	@RequestMapping(value = "/{batchId}/detail/export")
	public void exprotDetail(HttpServletResponse response,
			@PathVariable("batchId") Long batchPayRecordId) {
		response.setContentType("application/vnd.ms-excel");
		try {
			response.setHeader(
					"Content-Disposition",
					"attachment; filename="
							+ java.net.URLEncoder.encode(
									DateUtils.format(new Date(), "yyyy_MM_dd")
											+ "付款明细" + ".xls", "UTF-8"));

			OutputStream output = response.getOutputStream();
			paymetHandler.createDetailExcel(batchPayRecordId, output);
			output.close();
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
